
		AREA	|ARM$$code|,CODE,READONLY

		GET	OSLib:OSLib.Hdr.OS

		[ :LNOT: :DEF: NDEBUG
		IMPORT	log_printf
		]

		EXPORT	IOP321_dma_start_transfer
		EXPORT	IOP321_dma_wait_completion
		EXPORT	s3c2440_dma_start_transfer
		EXPORT	s3c2440_dma_wait_completion

	EXPORT	dma_start_transfer
	EXPORT	dma_wait_completion


DMA0_PHYS_BASE	*	&4B000000

DMA0_BASE	*	&C0300000

DISRC		*	0
DISRCC		*	4
DIDST		*	8
DIDSTC		*	&C
DCON		*	&10
DSTAT		*	&14
DMASKTRIG	*	&20



;-----------------------------------------------------------------------
;
; DMA on the Samsung S3C2440 CPU, as used in the A9home
;
;-----------------------------------------------------------------------

;&C0300000


; Start a DMA transfer using the S3C2440's DMA Controller Unit
;
; entry	a1 = physical address of source
;	a2 = physical address of destination
;	a3 = transfer length
; exit	a1 -> error block (0 iff no error)

s3c2440_dma_start_transfer
		STR	v1,[sp,#-4]!
		MRS	ip,CPSR
		LDR	a4,=DMA0_BASE
		TST	ip,#&0F
		SWIEQ	XOS_EnterOS

		;kick off the transfer

		STR	a1,[a4,#DISRC]
		MOV	a1,#0			;system bus, increment addr
		STR	a1,[a4,#DISRCC]
		STR	a2,[a4,#DIDST]
		STR	a1,[a4,#DIDSTC]		;system bus, increment addr, interrupt when TC reaches 0

		MOV	a1,#&D8000000
		ORR	a1,a1,#&00600000
		ORR	a1,a1,a3,LSR #4		;TC (words, 4 words/transfer)
		STR	a1,[a4,#DCON]

		MOV	a1,#2
		STR	a1,[a4,#DMASKTRIG]	;enable channel

		MOV	a1,#3
		STR	a1,[a4,#DMASKTRIG]	;trigger DMA

		MOV	a1,#0
dmastart_leave	MSR	CPSR_c,ip
		LDR	v1,[sp],#4
		MOV	pc,lr

error_active	DCD	0
		=	"DMA channel already active",0
		ALIGN


; Wait for completion of DMA transfer
;
; exit	a1 -> error block (0 iff no error)

s3c2440_dma_wait_completion
		MRS	ip,CPSR
		LDR	a4,=DMA0_BASE
		TST	ip,#&0F
		SWIEQ	OS_EnterOS
		LDR	a2,[a4,#DSTAT]
		B	s3dma_wait_test

s3dma_test_lp	SUBS	a1,a1,#1	;timed out?
		BLS	s3dmawt_timeout

s3dma_wait_lp	SUBS	a3,a3,#1
		BPL	s3dma_wait_lp

		LDR	a2,[a4,#DSTAT]
		MOV	a3,#&40000
s3dma_wait_test	TST	a2,#1<<20
		BNE	s3dma_test_lp

		MOV	a1,#0
s3dmawait_leave	MSR	CPSR_c,ip
		MOV	pc,lr

s3dmawt_timeout	ADR	a1,err_timeout
		MSR	CPSR_c,ip
		MOV	pc,lr

err_timeout	DCD	0
		=	"DMA timed out",0
		ALIGN



;-----------------------------------------------------------------------
;
; DMA on the IOP321 as used in the Iyonix
;
;-----------------------------------------------------------------------

;DMA0_PHYS_BASE	*	&FFFFE400
;DMA0_BASE	*	&F9BFE400

CCR		*	0
CSR		*	4
DAR		*	&C
NDAR		*	&10
BCR		*	&20


; Start a DMA transfer using the IOP321's DMA Controller Unit
;
; entry	a1 = DMA controller base address
;	a2 = physical address of first DMA chain descriptor
; exit	a1 -> error block (0 iff no error)

IOP321_dma_start_transfer
dma_start_transfer
		MRS	a4,CPSR
		TST	a4,#&0F
		SWIEQ	XOS_EnterOS

		;disable channel

		MOV	a3,#0
		STR	a3,[a1,#CCR]

		;clear error conditions

		MOV	a3,#&300
		ORR	a3,a3,#&2E
		STR	a3,[a1,#CSR]

		;check that the channel isn't active

		LDR	a3,[a1,#CSR]
		TST	a3,#1<<10
		ADRNE	a1,error_dma_busy
		BNE	dmast_leave

		;kick off the transfer

		STR	a2,[a1,#NDAR]
		MOV	a3,#1
		STR	a3,[a1,#CCR]

		MOV	a1,#0
dmast_leave	TST	a4,#&0F
		MSREQ	CPSR_c,a4
		MOV	pc,lr

error_dma_busy	DCD	0 ;Error_GeminusDMAChannelAlreadyActive
		=	"DMA channel already active",0
		ALIGN



; Wait for completion of DMA transfer
;
; entry	a1 =  DMA controller base address
; exit	a1 -> error block (0 iff no error)

;??? timeout value completely ignored atm

IOP321_dma_wait_completion
dma_wait_completion
		MRS	a4,CPSR
		TST	a4,#&0F
		SWIEQ	XOS_EnterOS

		LDR	a2,[a1,#CSR]
		B	dma_wait_test

dma_wait_lp	SUBS	a3,a3,#1	;back off for a bit rather than
		BPL	dma_wait_lp	;  reading status reg over and over

		LDR	a2,[a1,#CSR]
dma_wait_test	MOV	a3,#&80000
		TST	a2,#1<<10
		BNE	dma_wait_lp

		ANDS	a1,a2,#&2E
		TST	a4,#&0F
		MSREQ	CPSR_c,a4
		[ :DEF: NDEBUG
		ADRNE	a1,dma_failure
		MOV	pc,lr
		|
		MOVEQ	pc,lr
		STR	lr,[sp,#-4]!
		ADR	a1,dmafail_txt
		BL	log_printf
		ADR	a1,dma_failure
		LDR	pc,[sp],#4
		]

dma_failure	DCD	0  ;Error_GeminusDMATransferFailed
dmafail_txt	=	"DMA transfer failed %.8X",0
		ALIGN


;dma_read_reg	MRS	ip,CPSR
;		LDR	a4,=DMA0_BASE
;		TST	ip,#&0F
;		SWIEQ	XOS_EnterOS
;		LDR	a1,[a4,a1]
;		TST	ip,#&0F
;		MSREQ	CPSR_c,ip
;		MOV	pc,lr
;
;dma_write_reg	MRS	ip,CPSR
;		LDR	a4,=DMA0_BASE
;		TST	ip,#&0F
;		SWIEQ	XOS_EnterOS
;		STR	a2,[a4,a1]
;		TST	ip,#&0F
;		MSREQ	CPSR_c,ip
;		MOV	pc,lr

		END
